
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dac.h"


/* Private typedef -----------------------------------------------------------*/
enum {
	DMA_BUF_SIZE=1000,
};
typedef struct {
	PVOUT_DATA				pVout;
	u16						step;

	u16						timerFlag;
	TIM_TypeDef*			timOnOffPort;
	TIM_TimeBaseInitTypeDef timOnOffData;

	u32						sampling;	// 1uS(<=1mS), 2uS(<=2mS), ..., NuS(<=NmS)
	TIM_TypeDef*			timSamplingPort;
	TIM_TimeBaseInitTypeDef timSamplingData;
	u32						lenRising;
	u32						lenFalling;
	u16						dmaBuf[DMA_BUF_SIZE];
	DMA_Channel_TypeDef*	dmaChannel;
	DMA_InitTypeDef			dmaData;
	DAC_TypeDef*			dacPort;
	u32						dacChannel;
	DAC_InitTypeDef			dacData;
	u32						dacTrigger;
} DAC_DATA, *PDAC_DATA;
typedef void (*fxDMAIRQ)(PDAC_DATA pDac);

/* Private define ------------------------------------------------------------*/
#define DAC1_DHR12R1_ADDRESS	0x40007408	/* DAC1_OUT1 */
#define DAC1_DHR12R2_ADDRESS	0x40007414	/* DAC1_OUT2 */
#define DAC2_DHR12R1_ADDRESS	0x40009808	/* DAC2_OUT1 */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static DAC_DATA gDac[DAC_MAX] = {0,};
fxDMAIRQ gfxDmaIrq = NULL;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static u32 makeBuf(PDAC_DATA pDac, PVOUT_DATA pVout);
static void startDacDma(PDAC_DATA pDac);
static void stopDacDma(PDAC_DATA pDac);
static void timIRQHandler(PDAC_DATA pDac);
static void dmaIRQHandler(PDAC_DATA pDac);


void Dac_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure = {0,};
	NVIC_InitTypeDef NVIC_InitStructure = {0,};

	/* Enable GPIO clocks */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

	/* Configure PA[6:4] (DAC1_OUT1, DAC1_OUT2, DAC2_OUT1) as analog */
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* Configure PB[2:0], PA[10:8] in output pushpull mode */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);


	/* Enable TIM[14:12,4:2], DMA, DAC clocks */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC1, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC2, ENABLE);

	/* Enable the DMA2 and TIM[14:12] Interrupt */
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel4_IRQn;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel5_IRQn;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM12_IRQn;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM13_IRQn;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM14_IRQn;
	NVIC_Init(&NVIC_InitStructure);

	gDac[DAC_1].timOnOffPort = TIM12;
	gDac[DAC_1].timSamplingPort = TIM2;
	gDac[DAC_1].dmaData.DMA_PeripheralBaseAddr = DAC1_DHR12R1_ADDRESS;
	gDac[DAC_1].dmaChannel = DMA2_Channel3;
	gDac[DAC_1].dacPort = DAC1;
	gDac[DAC_1].dacChannel = DAC_Channel_1;
	gDac[DAC_1].dacTrigger = DAC_Trigger_T2_TRGO;

	gDac[DAC_2].timOnOffPort = TIM13;
	gDac[DAC_2].timSamplingPort = TIM3;
	gDac[DAC_2].dmaData.DMA_PeripheralBaseAddr = DAC2_DHR12R1_ADDRESS;
	gDac[DAC_2].dmaChannel = DMA2_Channel5;
	gDac[DAC_2].dacPort = DAC2;
	gDac[DAC_2].dacChannel = DAC_Channel_1;
	gDac[DAC_2].dacTrigger = DAC_Trigger_T3_TRGO;

	gDac[DAC_3].timOnOffPort = TIM14;
	gDac[DAC_3].timSamplingPort = TIM4;
	gDac[DAC_3].dmaData.DMA_PeripheralBaseAddr = DAC1_DHR12R2_ADDRESS;
	gDac[DAC_3].dmaChannel = DMA2_Channel4;
	gDac[DAC_3].dacPort = DAC1;
	gDac[DAC_3].dacChannel = DAC_Channel_2;
	gDac[DAC_3].dacTrigger = DAC_Trigger_T4_TRGO;

	for (u32 i=0; i<DAC_MAX; i++) {
		TIM_TimeBaseStructInit(&gDac[i].timOnOffData);
		gDac[i].timOnOffData.TIM_Period = 0xFFFF;
		gDac[i].timOnOffData.TIM_Prescaler = (36000 - 1);	// 500uS / 2KHz
		TIM_TimeBaseInit(gDac[i].timOnOffPort, &gDac[i].timOnOffData);

		TIM_TimeBaseStructInit(&gDac[i].timSamplingData);
		gDac[i].timSamplingData.TIM_Period = 0xFFFF;
		gDac[i].timSamplingData.TIM_Prescaler = 0x0;
		TIM_TimeBaseInit(gDac[i].timSamplingPort, &gDac[i].timSamplingData);

		gDac[i].dmaData.DMA_MemoryBaseAddr = (u32)&gDac[i].dmaBuf;
		gDac[i].dmaData.DMA_BufferSize = gDac[i].lenRising;
		gDac[i].dmaData.DMA_DIR = DMA_DIR_PeripheralDST;
		gDac[i].dmaData.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		gDac[i].dmaData.DMA_MemoryInc = DMA_MemoryInc_Enable;
		gDac[i].dmaData.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
		gDac[i].dmaData.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
		gDac[i].dmaData.DMA_Mode = DMA_Mode_Normal;
		gDac[i].dmaData.DMA_Priority = DMA_Priority_VeryHigh;
		gDac[i].dmaData.DMA_M2M = DMA_M2M_Disable;

		TIM_ITConfig(gDac[i].timOnOffPort, TIM_IT_Update, ENABLE);
		TIM_Cmd(gDac[i].timOnOffPort, ENABLE);
		TIM_DeInit(gDac[i].timOnOffPort);
	}

	gfxDmaIrq = dmaIRQHandler;
}

void Dac_Proc(u32 mode, u32 modeChanged)
{
	if (modeChanged){
		if ((MODE_ADCIN == mode) || (MODE_REMOTE_VI2MD == mode)) {
			gfxDmaIrq = stopDacDma;
		} else {
			gfxDmaIrq = dmaIRQHandler;
		}
	}
}

void Dac_Set_Sel(u32 dac, u32 on)
{
	switch (dac) {
	case DAC_1:
		GPIO_WriteBit(GPIOB, GPIO_Pin_0, on ? Bit_SET : Bit_RESET);
		break;
	case DAC_2:
		GPIO_WriteBit(GPIOB, GPIO_Pin_1, on ? Bit_SET : Bit_RESET);
		break;
	case DAC_3:
		GPIO_WriteBit(GPIOB, GPIO_Pin_2, on ? Bit_SET : Bit_RESET);
		break;
	}
}

u32 Dac_Get_Sel(u32 dac)
{
	switch (dac) {
	case DAC_1:
		return GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0);
	case DAC_2:
		return GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1);
	case DAC_3:
		return GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2);
	}

	return (u32)-1;
}

void Dac_Set_Flt(u32 dac, u32 on)
{
	switch (dac) {
	case DAC_1:
		GPIO_WriteBit(GPIOA, GPIO_Pin_8, on ? Bit_SET : Bit_RESET);
		break;
	case DAC_2:
		GPIO_WriteBit(GPIOA, GPIO_Pin_9, on ? Bit_SET : Bit_RESET);
		break;
	case DAC_3:
		GPIO_WriteBit(GPIOA, GPIO_Pin_10, on ? Bit_SET : Bit_RESET);
		break;
	}
}

u32 Dac_Get_Flt(u32 dac)
{
	switch (dac) {
	case DAC_1:
		return GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_8);
	case DAC_2:
		return GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_9);
	case DAC_3:
		return GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_10);
	}

	return (u32)-1;
}

void Dac_Out_Host(PVOUT_DATA pVout, u32 timerStart)
{
	for (u32 i=0; i<DAC_MAX; i++) {
		TIM_DeInit(gDac[i].timOnOffPort);
		TIM_Cmd(gDac[i].timSamplingPort, DISABLE);
		DMA_DeInit(gDac[i].dmaChannel);
		DAC_DeInit(gDac[i].dacPort);

		gDac[i].dacData.DAC_Trigger = DAC_Trigger_None;
		gDac[i].dacData.DAC_WaveGeneration = DAC_WaveGeneration_None;
		gDac[i].dacData.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
		DAC_Init(gDac[i].dacPort, gDac[i].dacChannel, &gDac[i].dacData);
		DAC_Cmd(gDac[i].dacPort, gDac[i].dacChannel, ENABLE);
		if (DAC_Channel_1 == gDac[i].dacChannel) {
			DAC_SetChannel1Data(gDac[i].dacPort, DAC_Align_12b_R, 0);
		} else {
			DAC_SetChannel2Data(gDac[i].dacPort, DAC_Align_12b_R, 0);
		}
	}


	if (pVout) {
		for (u32 i=0; i<DAC_MAX; i++) {
			u32 idx = makeBuf(&gDac[i], &pVout[i]);
			printf("DAC_%d %d SamplingRate %d uSec\r\n", i+1, idx, gDac[i].sampling);

			gDac[i].timSamplingData.TIM_Period = (72*gDac[i].sampling - 1);//71;	// 1 uS
			TIM_TimeBaseInit(gDac[i].timSamplingPort, &gDac[i].timSamplingData);
			TIM_SelectOutputTrigger(gDac[i].timSamplingPort, TIM_TRGOSource_Update);

			gDac[i].timOnOffData.TIM_Period = (gDac[i].pVout->dwToff*2 - 1);
			TIM_TimeBaseInit(gDac[i].timOnOffPort, &gDac[i].timOnOffData);
			TIM_ITConfig(gDac[i].timOnOffPort, TIM_IT_Update, ENABLE);

			if (timerStart) {
				TIM_Cmd(gDac[i].timOnOffPort, ENABLE);
			}
		}
	}
}
u32 Dac_Out_Trigger(u32 rising)
{
	u32 maxTime = 0;

	if (rising) {
		gDac[DAC_1].step = STEP_TOFF;
		gDac[DAC_2].step = STEP_TOFF;
		gDac[DAC_3].step = STEP_TOFF;

		for (u32 i=0, time; i<DAC_MAX; i++) {
			time = gDac[i].lenRising * gDac[i].sampling;
			if (maxTime < time) {
				maxTime = time;
			}
		}
	} else {
		gDac[DAC_1].step = STEP_TON;
		gDac[DAC_2].step = STEP_TON;
		gDac[DAC_3].step = STEP_TON;

		for (u32 i=0, time; i<DAC_MAX; i++) {
			time = gDac[i].lenFalling * gDac[i].sampling;
			if (maxTime < time) {
				maxTime = time;
			}
		}
	}
	startDacDma(&gDac[DAC_1]);
	startDacDma(&gDac[DAC_2]);
	startDacDma(&gDac[DAC_3]);

	return maxTime;
}

void Dac_Out_Set_Step(u32 dac, u32 step)
{
	switch (dac) {
	case DAC_1:
		gDac[DAC_1].step = step;
		break;
	case DAC_2:
		gDac[DAC_2].step = step;
		break;
	case DAC_3:
		gDac[DAC_3].step = step;
		break;
	}
}
u32 Dac_Out_Get_Step(u32 dac)
{
	switch (dac) {
	case DAC_1:
		return gDac[DAC_1].step;
	case DAC_2:
		return gDac[DAC_2].step;
	case DAC_3:
		return gDac[DAC_3].step;
	}

	return (u32)-1;
}



static u32 makeBuf(PDAC_DATA pDac, PVOUT_DATA pVout)
{
	u32 dwTrs[VDATA_TR_STEP] = {pVout->dwTr1, pVout->dwTr2, pVout->dwTr3, pVout->dwTr4};
	u32 dwVrs[VDATA_TR_STEP] = {pVout->dwVr1, pVout->dwVr2, pVout->dwVr3, pVout->dwVr4};
	u32 total = 0, sampling, idx, sidx;
	float delta, level;

	pDac->pVout = pVout;
	pDac->step = STEP_TOFF;
	pDac->timerFlag = 0;
	for (u32 i=0; i<VDATA_TR_STEP; i++) {
		if (dwTrs[i]) {
			total += dwTrs[i];
		} else {
			break;
		}
	}
	total += pVout->dwTf1;

	sampling = (total / DMA_BUF_SIZE) + 1;
	if (0 == (total % DMA_BUF_SIZE)) {
		sampling--;
	}
	pDac->sampling = sampling;

	idx = 0;
	level = 0;
	for (u32 i=0; i<VDATA_TR_STEP; i++) {
		if (dwTrs[i]) {
			delta = (float)((dwVrs[i] - level) / dwTrs[i]) * sampling;
			for (sidx=0; sidx<dwTrs[i]; sidx+=sampling) {
				level += delta;
				pDac->dmaBuf[idx++] = (u16)(level + 0.5) << 1;
			}
			if (sidx) {
				pDac->dmaBuf[idx-1] = (dwVrs[i] + (int)pVout->dwOffset) << 1;
			}
			level = dwVrs[i];
		} else {
			break;
		}
	}
	pDac->lenRising = idx;

	if (0 == pVout->dwTf1) {
		pDac->dmaBuf[idx++] = 0;
	} else {
		delta = (level / pVout->dwTf1) * sampling;
		for (sidx=0; sidx<pVout->dwTf1; sidx+=sampling) {
			level -= delta;
			if (0 > level) {
				level = 0;
			}
			pDac->dmaBuf[idx++] = (u16)(level + 0.5) << 1;
		}
		if (sidx) {
			pDac->dmaBuf[idx-1] = 0;
		}
	}
	pDac->lenFalling = idx - pDac->lenRising;

	return idx;
}


static void startDacDma(PDAC_DATA pDac)
{
	pDac->dacData.DAC_Trigger = pDac->dacTrigger; //
	DAC_Init(pDac->dacPort, pDac->dacChannel, &pDac->dacData);	//
	DAC_Cmd(pDac->dacPort, pDac->dacChannel, ENABLE);	//
	if (STEP_TOFF == pDac->step) {
		pDac->step = STEP_TR;
		pDac->dmaData.DMA_MemoryBaseAddr = (u32)&pDac->dmaBuf[0];
		pDac->dmaData.DMA_BufferSize = pDac->lenRising;
	} else /*if (STEP_TON == pDac->step)*/ {
		pDac->step = STEP_TF;
		pDac->dmaData.DMA_MemoryBaseAddr = (u32)&pDac->dmaBuf[pDac->lenRising];
		pDac->dmaData.DMA_BufferSize = pDac->lenFalling;
	}
	DMA_Init(pDac->dmaChannel, &pDac->dmaData);
	DMA_Cmd(pDac->dmaChannel, ENABLE);
	DAC_DMACmd(pDac->dacPort, pDac->dacChannel, ENABLE);
	DMA_ITConfig(pDac->dmaChannel, DMA_IT_TC, ENABLE);
	TIM_Cmd(pDac->timSamplingPort, ENABLE);
}
static void stopDacDma(PDAC_DATA pDac)
{
	TIM_Cmd(pDac->timSamplingPort, DISABLE);
	DMA_DeInit(pDac->dmaChannel);

	if (DAC_Channel_1 == pDac->dacChannel) {
		DAC_SetChannel1Data(pDac->dacPort, DAC_Align_12b_R, 0);
	} else {
		DAC_SetChannel2Data(pDac->dacPort, DAC_Align_12b_R, 0);
	}
}

static void timIRQHandler(PDAC_DATA pDac)
{
	//+++ stopDacTim()
	if (0 == pDac->timerFlag) {
		pDac->timerFlag = 1;
		return;
	}
	pDac->timerFlag = 0;
	TIM_Cmd(pDac->timOnOffPort, DISABLE);
	TIM_DeInit(pDac->timOnOffPort);
	//--- stopDacTim()

	//+++ startDacDma()
	pDac->dacData.DAC_Trigger = pDac->dacTrigger; //
	DAC_Init(pDac->dacPort, pDac->dacChannel, &pDac->dacData);	//
	DAC_Cmd(pDac->dacPort, pDac->dacChannel, ENABLE);	//
	if (STEP_TOFF == pDac->step) {
		pDac->step = STEP_TR;
		pDac->dmaData.DMA_MemoryBaseAddr = (u32)&pDac->dmaBuf[0];
		pDac->dmaData.DMA_BufferSize = pDac->lenRising;
	} else /*if (STEP_TON == pDac->step)*/ {
		pDac->step = STEP_TF;
		pDac->dmaData.DMA_MemoryBaseAddr = (u32)&pDac->dmaBuf[pDac->lenRising];
		pDac->dmaData.DMA_BufferSize = pDac->lenFalling;
	}
	DMA_Init(pDac->dmaChannel, &pDac->dmaData);
	DMA_Cmd(pDac->dmaChannel, ENABLE);
	DAC_DMACmd(pDac->dacPort, pDac->dacChannel, ENABLE);
	DMA_ITConfig(pDac->dmaChannel, DMA_IT_TC, ENABLE);
	TIM_Cmd(pDac->timSamplingPort, ENABLE);
	//--- startDacDma()
}
static void dmaIRQHandler(PDAC_DATA pDac)
{
	//+++ stopDacDma()
	TIM_Cmd(pDac->timSamplingPort, DISABLE);
	DMA_DeInit(pDac->dmaChannel);
	//--- stopDacDma()

	//+++ startDacTim()
	if (STEP_TR == pDac->step) {
		pDac->step = STEP_TON;
		pDac->timOnOffData.TIM_Period = (pDac->pVout->dwTon*2 - 1);
	} else /*if (STEP_TF == pDac->step)*/ {
		pDac->step = STEP_TOFF;
		pDac->timOnOffData.TIM_Period = (pDac->pVout->dwToff*2 - 1);
	}
	TIM_TimeBaseInit(pDac->timOnOffPort, &pDac->timOnOffData);
	TIM_ITConfig(pDac->timOnOffPort, TIM_IT_Update, ENABLE);
	TIM_Cmd(pDac->timOnOffPort, ENABLE);
	//--- startDacTim()
}


void TIM12_IRQHandler(void)
{
	//if (TIM_GetITStatus(TIM12, TIM_IT_Update) != RESET) {
	//	TIM_ClearITPendingBit(TIM12, TIM_IT_Update);
	if ((TIM12->SR & TIM_IT_Update) && (TIM12->DIER & TIM_IT_Update)) {
		TIM12->SR = (u16)~TIM_IT_Update;

		timIRQHandler(&gDac[DAC_1]);
	}
}
void TIM13_IRQHandler(void)
{
	//if (TIM_GetITStatus(TIM13, TIM_IT_Update) != RESET) {
	//	TIM_ClearITPendingBit(TIM13, TIM_IT_Update);
	if ((TIM13->SR & TIM_IT_Update) && (TIM13->DIER & TIM_IT_Update)) {
		TIM13->SR = (u16)~TIM_IT_Update;

		timIRQHandler(&gDac[DAC_2]);
	}
}
void TIM14_IRQHandler(void)
{
	//if (TIM_GetITStatus(TIM14, TIM_IT_Update) != RESET) {
	//	TIM_ClearITPendingBit(TIM14, TIM_IT_Update);
	if ((TIM14->SR & TIM_IT_Update) && (TIM14->DIER & TIM_IT_Update)) {
		TIM14->SR = (u16)~TIM_IT_Update;

		timIRQHandler(&gDac[DAC_3]);
	}
}

void DMA2_Channel3_IRQHandler(void)
{
	//if (DMA_GetITStatus(DMA2_IT_TC3)) {
	//	DMA_ClearITPendingBit(DMA2_IT_TC3);
	if (DMA2->ISR & DMA2_IT_TC3) {
		DMA2->IFCR = DMA2_IT_TC3;

		gfxDmaIrq(&gDac[DAC_1]);
	}
}
void DMA2_Channel4_IRQHandler(void)
{
	//if (DMA_GetITStatus(DMA2_IT_TC4)) {
	//	DMA_ClearITPendingBit(DMA2_IT_TC4);
	if (DMA2->ISR & DMA2_IT_TC4) {
		DMA2->IFCR = DMA2_IT_TC4;

		gfxDmaIrq(&gDac[DAC_3]);
	}
}
void DMA2_Channel5_IRQHandler(void)
{
	//if (DMA_GetITStatus(DMA2_IT_TC5)) {
	//	DMA_ClearITPendingBit(DMA2_IT_TC5);
	if (DMA2->ISR & DMA2_IT_TC5) {
		DMA2->IFCR = DMA2_IT_TC5;

		gfxDmaIrq(&gDac[DAC_2]);
	}
}

